struct ECSB2Greedy <: ECSB2OptimisationAlgorithm end

function optimise_linear_sqrtlinear(instance::CombinatorialInstance, ::ECSB2Greedy, 
                                    linear::Dict{T, Float64}, sqrtlinear::Dict{T, Float64}, epsilon::Float64, d::Int, verbose::Int; with_trace::Bool=false) where T
  directions = Set(keys(linear))
  sol = T[]

  # As long as possible, add new arms to the solution to improve the expected reward. 
  t0 = now()
  nIter = 0
  while true
    nIter += 1

    # Pick the best direction to improve the reward. 
    bestReward = 0.0
    bestDirection = nothing
    for d in directions
      newSol = copy(sol)
      push!(newSol, d)
      if ! is_feasible(instance, newSol)
        continue
      end

      reward = sum(linear[arm] for arm in keys(linear) if in(arm, newSol)) + sqrt(sum(sqrtlinear[arm] for arm in keys(linear) if in(arm, newSol)))

      if reward > bestReward
        bestReward = reward
        bestDirection = d
      end
    end

    # If no direction could be found, done! 
    if bestDirection == nothing
      break
    end
    
    # Update the solution and ensure this direction will never be tried again. 
    push!(sol, bestDirection)
    delete!(directions, bestDirection)

    # If there is no more a direction to explore, done! 
    if isempty(directions) 
      break
    end
  end
  t1 = now()

  if with_trace
    runDetails = ECSB2Details()
    runDetails.nIterations = nIter
    runDetails.bestLinearObjective = sum(linear[arm] + sqrtlinear[arm] for arm in keys(linear) if in(arm, sol))
    runDetails.bestNonlinearObjective = sum(linear[arm] for arm in keys(linear) if in(arm, sol)) + sqrt(sum(sqrtlinear[arm] for arm in keys(linear) if in(arm, sol)))
    runDetails.solverTimes = Float64[(t1 - t0).value]
    return sol, runDetails
  else
    return sol
  end
end
